﻿# coding: utf-8

import os
from operator import itemgetter

from django.contrib.auth import authenticate
from django.http import JsonResponse
from django.shortcuts import redirect
from django.middleware import csrf
from django.views.decorators.csrf import csrf_exempt

from lib.sms import sender
from lib.loginout import login_sys, logout_sys
from project.settings import USER_TYPE, MOBILE_OS_CHOICES, IOS_CHECKING
from services.datamodel.device.models import devicemanage
from services.datamodel.student.models import mm_Student
# from services.datamodel.checkin.models import mm_Checkin
from services.datamodel.share import BusinessCode
from services.datamodel.delivery.models import mm_DeliveryPvUv
from django.core.cache import cache
import logging
model_logger = logging.getLogger("datamodel")
from services.datamodel.absorbed.models import mm_AllData
from datetime import date
import json


def check_parameter(os_type, device_token):
    ret, msg = 1, ""
    if os_type not in map(itemgetter(0), MOBILE_OS_CHOICES):
        msg = "unsupported ostype"
    elif len(device_token) > 100:
        msg = "invalid devicetoken"
    else:
        ret = 0

    return dict(retcode=ret, msg=msg)


def check_mobile_login(func):
    @csrf_exempt
    def inner(request):
        # h = cache.get("15167049565_test")
        # if h:
        #     return JsonResponse({'retcode': 1, 'msg': 'The information of this account has been deleted，Unable to login'})
        post_para = request.POST
        is_elephant = int(post_para.get('is_elephant', '0'))
        code = post_para.get('code', '')
        share_code = post_para.get("share_code", None)
        pad_token = post_para.get('pad_token', '')
        # is_event_proxy = int(post_para.get('is_event_proxy', '0'))

        username = post_para.get('username', '')
        password = post_para.get('password', '')
        os_type = post_para.get('ostype', '')
        device_token = post_para.get('devicetoken', '')
        description = post_para.get('description', '')
        # register_from = post_para.get('register_from', '1')

        # wni: 这个openid是微信浏览器验证码登录时传过来，如果没有和学生帐号绑定的则把它绑定给学生帐号
        openid = post_para.get('openid', '')
        provincename = post_para.get('provincename', None)
        cityname = post_para.get('cityname', None)
        nickname = post_para.get('nickname', None)
        avatar = post_para.get('avatar', None)
        gender = post_para.get('gender', None)

        # wni: 下面这个wechat_openid 微信浏览器，如果openid已经绑定，直接用绑定的用户登录(相当于通过openid登录)
        wechat_openid = post_para.get('wechat_openid', '')
        wechat_unionid = post_para.get('wechat_unionid', None)
        # applet_openid  小程序openid用于登录  unionid用于绑定老用户
        applet_openid = post_para.get('applet_openid', '')
        unionid = post_para.get('unionid', '')

        # 参数: channel  0:默认 1:(h5测评分享链接)    2:(APP测评分享链接)   3:(APP课程海报分享)   4:(APP邀请有礼海报)
        # 5:(学籍卡海报分享)      参数名：  channel
        channel = int(post_para.get('channel', '0'))
        label = post_para.get('p', 0)
        evach = post_para.get('evach', '')  # 测评渠道码
        # wni:launch_id和launch_dynamic_id参数不能传字符串"0"
        launch_id = int(post_para.get('launch_id', '0'))  #投放ID
        launch_dynamic_id = int(post_para.get('launch_dynamic_id', '0'))  #活码ID
        resp = check_parameter(os_type, device_token)
        is_app_wectch = post_para.get('is_app_wectch', 0)
        mini = post_para.get('mini', '')
        o_id = post_para.get('o_id', '')
        un_id = post_para.get('un_id', '')
        if resp['retcode'] != 0:
            pass
        elif code:
            if label:  # 微信里面绑定手机号
                is_app = None
                if not wechat_openid and not wechat_unionid:
                    return JsonResponse({'retcode': 1, 'msg': 'openid为空'})
                # 修改
                resp = sender.checkcode(BusinessCode.MLOGIN, username, code)
                if resp["retcode"] == 0:
                    student = mm_Student.select_related("user").filter(openid=wechat_openid).last()
                    # 这里是app微信登入的时候获取缓存
                    # user_unionid = cache.get('user_unionid_'+str(wechat_unionid))
                    if wechat_unionid:
                        is_app = 1
                        student = mm_Student.select_related("user").filter(unionid=wechat_unionid).last()
                    if student:
                        # 针对投放的微信uv。。。
                        if launch_id:
                            mm_DeliveryPvUv.set_two_uv(launch_id, student.id)
                        # 这种情况是针对原来老的测评用户--需要删除当前openid注册的账号，并且把openid更新绑定到老的手机号上
                        resp = mm_Student.delete_student_for_openid(student.id, mobile=username, openid=wechat_openid,
                                                                    unionid=wechat_unionid, is_app=is_app)
            else:
                resp = handler.code_login(username, code, openid, share_code, provincename=provincename,
                                          cityname=cityname, nickname=nickname, avatar=avatar, gender=gender,
                                          channel=channel, launch_id=launch_id, unionid=unionid)
        elif wechat_openid or is_app_wectch:  # 微信openid这册/登录
            student = mm_Student.select_related("user").filter(openid=wechat_openid).last()
            if is_app_wectch:
                student = mm_Student.select_related("user").filter(unionid=unionid).last()
            if student:
                resp["user"] = student.user
                resp["student"] = student
                resp["newuser"] = 0
                # 更新unionid
                student.unionid = unionid
                student.save()
                if launch_id:
                    mm_DeliveryPvUv.set_one_uv(launch_id, wechat_openid)
                if student.eva_channel == 0 and evach:  #第一次做测评绑定测评渠道
                    from services.datamodel.evaluation.models import mm_EvaluationChannel
                    ec = mm_EvaluationChannel.filter(evach=evach).first()
                    if ec:
                        evach_channel_id, evach_channel_name = ec.id, ec.name
                        ec.used += 1
                        ec.save()
                        student.eva_channel = evach_channel_id
                        student.eva_channel_name = evach_channel_name
                        student.save()
            else:
                # 这里是新增微信openid登入
                state = mm_Student.add_student_for_openid(openid, channel, share_code, provincename=provincename,
                                                          cityname=cityname, nickname=nickname, avatar=avatar,
                                                          gender=gender, evach=evach, launch_id=launch_id,
                                                          launch_dynamic_id=launch_dynamic_id, unionid=unionid)
                if state["retcode"] == 0:
                    if launch_id:
                        mm_DeliveryPvUv.set_one_uv(launch_id, wechat_openid)
                    resp.update(handler.common("", "", user=state["user"], openid=openid, newuser=state['newuser']))
                else:
                    resp.update(**state)

        elif applet_openid and unionid:
            from services.datamodel.speech_applet.models import mm_SpeechActiveUser
            student = mm_Student.select_related("user").filter(applet_openid=applet_openid, unionid=unionid).last()
            if student:
                from services.datamodel.student.models import mm_StudentChannel
                resp["user"] = student.user
                resp["student"] = student
                resp["newuser"] = 0
                active_user = mm_SpeechActiveUser.create_active_user(student.id)
                resp['active_user_id'] = active_user.get('active_user_id')
                resp['Workplace_DNA'] = mm_StudentChannel.get_Workplace_DNA(student.id)
            else:
                # 这里是新增小程序unionid登入
                state = mm_Student.add_student_for_unionid(unionid, channel, share_code, applet_openid=applet_openid,
                                                           nickname=nickname, avatar=avatar, evach=evach)
                if state["retcode"] == 0:
                    resp.update(handler.common("", "", user=state["user"], openid=openid, newuser=state['newuser'],))
                    resp['active_user_id'] = state['active_user_id']
                    resp['Workplace_DNA'] = state['Workplace_DNA']
                else:
                    resp.update(**state)
        elif mini:
            from datetime import datetime
            student = mm_Student.select_related("user").filter(mobile=username).last()
            if student:
                resp["user"] = student.user
                resp["student"] = student
                resp["newuser"] = 0
                if not student.zb_openid:
                    student.created_at = datetime.now()
            else:
                state = mm_Student.addStudent(username=username, realname=nickname, avatar=avatar, channel=channel,
                                              phonenumber=username)
                if state["retcode"] == 0:
                    student = mm_Student.select_related("user").filter(id=state["id"]).last()
                    # student.source = 13
                    # student.zb_unionid = un_id
                    # student.zb_openid = o_id
                    # student.save()
                    resp["user"] = student.user
                    resp["student"] = student
                else:
                    resp.update(**state)
            if not student.zb_openid:
                student.zb_openid = o_id
                mm_AllData.update_all_num(num=13)
                # 记录当天新增的用户数据
                today = str(date.today())
                user_arr = cache.get(today)
                if not user_arr:
                    cache.set(today, json.dumps([student.id]), None)
                else:
                    user_list = json.loads(user_arr)
                    user_list.append(student.id)
                    cache.set(today, json.dumps(user_list), None)
            student.zb_unionid = un_id
            student.source = 13
            student.save()
            # mm_AllData.update_all_num(num=12)
        else:
            resp = handler.common(username, password)

        # update with login success
        if resp['retcode'] == 0:
            devicemanage.update_user_device(device_token, resp["user"].id, os_type, description, pad_token)

            # only one device login
            login_sys(request, resp["user"], is_elephant=1)
            # update DB, cache, session
            handler.update_session(request, resp["student"], is_elephant)
            # update applet_openid unioinid
            resp.update({"applet_openid": resp['student'].applet_openid, "unionid": resp['student'].unionid,
                         "identity": resp['student'].identity})
            # update message for response
            resp.update(func(resp["student"], pad_token, request.session.session_key))

        resp.pop("user", None)
        resp.pop("student", None)
        # if username == "15167049565":
        #     u = mm_Student.get_or_default(mobile=username)
        #     u_id = u.user_id
        #     u.delete()
        #     from django.contrib.auth.models import User
        #     User.objects.get(id=u_id).delete()
        #     cache.set("15167049565_test", 1)
        return JsonResponse(resp)

    return inner


class ReqHandler(object):
    def __init__(self):
        self.curDir = os.path.dirname(os.path.abspath(__file__))

    @staticmethod
    def login(request):
        csrf.get_token(request)
        return redirect("/teacher/login/login.html")

    @staticmethod
    def loginReq(request):
        username = request.POST.get("username")
        password = request.POST.get("password")
        user = ReqHandler.student_authenticate(username=username, password=password)
        resp = {"retcode": 1}

        if user is None:
            resp["msg"] = "用户名或者密码错误"
        elif not user.is_active:
            resp["msg"] = "用户已经被禁用"
        elif not hasattr(user, "student"):
            resp["msg"] = "请使用学生账户登录"
        else:
            # login(request, user)
            login_sys(request, user)
            student = user.student
            request.session.update({
                "ut": USER_TYPE.STDUENT,
                "studentid": student.id,
                "realname": student.realname,
                "schoolid": student.schoolid or 0,
                "gradeid": student.gradeid or 0,
                "classid": student.classid or 0,
            })
            resp["realname"] = student.realname
            resp["retcode"] = 0

        return JsonResponse(resp)

    @staticmethod
    def logoutReq(request):
        # logout(request)
        logout_sys(request)
        return JsonResponse({"retcode": 0})

    @staticmethod
    def update_session(request, student, is_elephant=0):
        request.session.update({
            "ut": student.level,
            "studentid": student.id,
            "uid": student.user_id,
            "realname": student.nick_name,
            "share_code": student.share_code
        })
        request.session.save()

    @staticmethod
    def common(username, password, user=None, openid=None, newuser=None):
        # 正常登入
        ret, msg = 1, ""
        if user is None:
            user = ReqHandler.student_authenticate(username=username, password=password)
        student = None

        if user is None:
            msg = "用户名或密码错误"
        elif not user.is_active:
            msg = "帐号被禁用"
        elif not hasattr(user, "student"):
            msg = "请使用学生账户登录"
        else:
            ret = 0
            student = user.student
            if openid and student.openid != openid:
                student.openid = openid
                student.save()

        return dict(retcode=ret, msg=msg, student=student, user=user, newuser=newuser)

    def elephant_login(self, username, password):
        # 大象错题本, 不需要传devicetoken, 因为不涉及到推送
        # 另外瞎传会影响原有app推送, 故特殊处理之
        resp = self.common(username, password)

        return resp

    # def pad_login(self, username, password, pad_token):
    #     # pad登入后的推送方式用老卫的es push, 使用pad token来推送
    #     # 所以不需要有盟推送的device token
    #     resp = self.common(username, password)
    #
    #     if resp["retcode"] == 0:
    #         student = resp["student"]
    #         resp.update(mm_MamPad.login_pad(student.user_id, pad_token, student.classid, student.schoolid))
    #
    #     return resp

    def code_login(self, username, code, openid, share_code=None, gender=None,
                   provincename=None, cityname=None, nickname=None, avatar=None, channel=0, launch_id=None, unionid=None):
        # 检查code是否合法
        # 检查该username是否已经存在
        # 存在则正常登入, 不存在则默认注册再登入
        resp = sender.checkcode(BusinessCode.MLOGIN, username, code)
        if resp["retcode"] == 0:
            state = mm_Student.add_student_if_not_exist(username, openid, share_code, provincename=provincename,
                                                        cityname=cityname, nickname=nickname, avatar=avatar,
                                                        gender=gender, channel=channel, launch_id=launch_id,
                                                        unionid=unionid)
            if state["retcode"] == 0:
                resp.update(**self.common("", "", user=state["user"], openid=openid, newuser=state['newuser']))
            else:
                resp.update(**state)

        return resp

    @staticmethod
    def event_proxy(username, password):
        # 正常登入
        ret, msg = 1, ""
        user = ReqHandler.student_authenticate(username=username, password=password)
        student = None

        if user is None:
            msg = "用户名或密码错误"
        elif not user.is_active:
            msg = "学生已经被禁用"
        elif not hasattr(user, "student") or \
            user.id not in (getattr(user.student, "one_proxy_id"), getattr(user.student, "two_proxy_id")) or \
            (user.id == getattr(user.student, "one_proxy_id") and not getattr(user.student, "event_proxy_on")):
            msg = "请使用正确的代理商账号登陆"
        else:
            ret = 0
            student = user.student

        return dict(retcode=ret, msg=msg, student=student, user=user)

    @staticmethod
    @check_mobile_login
    def m_login(student, pad_token, session_key):
        """
        移动端登入

        验证: username, code, ostype, devicetoken
        普通: username, password, ostype, devicetoken
        大象: username, password, ostype, is_elephant=1
        平板: username, password, ostype, pad_token=mac_address

        ostype: settings.MOBILE_OS_CHOICES
        devicetoken: youmeng push
        pad_token: pad mac address to es push

        """

        resp = mm_Student.getDetailInfo(student, for_login=True, for_pad=pad_token)
        resp["sessionid"] = session_key
        resp["IOS_CHECKING"] = IOS_CHECKING
        # checkin = mm_Checkin.get_or_default(user_id=student.user_id)
        # resp['is_today_check_in'] = True if checkin and checkin.last_day.date() == datetime.datetime.today().date()
        # else False

        return resp

    @staticmethod
    @csrf_exempt
    def mlogout(request):
        # mm_MamPad.logout_pad(request.user.id)
        devicemanage.filter(user__id=request.user.id).update(pad_token=None)
        if hasattr(request.user, "student"):
            request.user.student.login_status = False
            request.user.student.save()
        is_elephant = request.session.get('is_elephant')
        logout_sys(request, is_elephant)
        return JsonResponse({"retcode": 0})

    @staticmethod
    def student_authenticate(username, password):
        student = mm_Student.get_or_default(phonenumber=username)
        if student:
            user = authenticate(username=student.user.username, password=password)
            return user
        else:
            # 此处传入的username是app端传入的参数, 已经附带了前缀, 此添加前缀的步骤理应由后端负责, 但是当前app端已经做了
            user = authenticate(username=username, password=password)
            return user if user and hasattr(user, 'student') else None


handler = ReqHandler()